package com.ly.demo.skt;

/**
 * @author liuyang
 * @des
 * @Version 1.0
 * @Date: 26/09/2021 16:53
 */

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;

import static sun.security.pkcs11.wrapper.Functions.toHexString;

/**
 * @Description 获取收银台地址demo
 * @Author 80258206
 * @Date 2021-03-19 15:35
 * @Version 1.0
 */
@Slf4j
@Service
public class OpenApiDemoService {
    /**
     * 加签私钥
     */
    private final static String RSA_PRI_KEY =
        "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDI35AZFjqcwGpejgySyHPLdCuwu+1\n"
            + "bWCB1rqManAPdZTWvMUijMDI5dRkSF58/oGogCH6RLQivCxHSDaU6mhHHVdDFjO3saIVo/Rnptv9IadJ\n"
            + "YutvAD4y51UqEkcIwzI0KMps0qYlgSKBE6X+19LfyMptwixFb6tSpTdYDdixwPzbL3q0sARbA4vp+vdt\n"
            + "tZYXozcJEDnhgXD7yXZnkFdXNVeanEmgw0OwO5UGdOCwQGBVdZEcGzggr3zYQ2vahDBFGjZIcYX2QLvr\n"
            + "aQICbYPvsV5OQ9ydEHrk7aWb5WQkhwH/qwV0EExrzJvN74vrDkj28Og9O6VJVnqPuaSuTItzZAgMBAAE\n"
            + "CggEANKnYP5uCVmJkANJBHaKMKUUVx0od2prqN7BHdsx8fujwADRtlMsn/8RhhErJJ4dJC4juleU2p53\n"
            + "BWE7XiNun2Zj4GTLvldF5WKMyzgF6QGPuD/E9d8cb4AS5erQ0M1MNjyThaBciuymPS0Hkh7HXIBqAgis\n"
            + "TrAOPKawMde/firWw//jS7zhpa/fA+0DCDRKMmmVNCMfyHbD706N0yChAgtHnsqiRge+2xGCo3tPsq+r\n"
            + "7eI7SZON1/KsqTqGX1vOHx9wtGB5mBJ/gP3J/qWyC56BDXJuvYDCTRaNbE0YLifuZQO3oj+G1Bu1tvMN\n"
            + "dFkA92xVJ3i5jIC2eytm6AG87OQKBgQDtwj47ubPCvYWdo/muV64RF/jQDFO6idDIR/HCc64fBT6/M4O\n"
            + "/mYzNztNwdMwCB08mYFlwg42TLixsmeUy2qMeZ/1Om3YVrFsezr2H8Vw+COw0sJp13y2nAYzF2yflzS7\n"
            + "qCfrBx2Zh29i/0sRuSClHuXpe9qRYcTamUo8c+XtauwKBgQDYSNyutjkOOBc7frFDrLoknRKyiWw1dIV\n"
            + "NakaHBLKO5SNN4hsvuFqqTW2MY+skwyaR54X7Qju8W1aa87p1XeLBLKL2h4M6UAco59x/69dS4SMnYN4\n"
            + "ysUG23Dmmaae5dJXUB7SOVltrN7/YBui0cqEhOpMJTTXZSLohifcCM5r/ewKBgHwVYttSyIE63e/usxE\n"
            + "NC3g6VY1m0Y/J+x97hK3iJ55i42NwJDMrlPOYHHtVSV9Jp0I1CJiS36FPeLnY+2g1+OmWhfmvYspe4FN\n"
            + "MvFelXGm3yGabQJGBv1aolWpxPPpOwkw8lxTo1wL9dLpv6jpQCNM49qd2+0B5HXdiIPSTM5CfAoGAXTb\n"
            + "BzZaBboxkDuMiWM1XiDId/c5WUY9/aAb2kHhI0GcW2RkqqF1mzeEC5q+lhzmIJPfIeapo/lvLLor+gFj\n"
            + "PQnwPW/q5ZudYvpt3H7awHWskcHNCMEzOypWNTxhYDgieDjyn53R2f/YN+3e20RZaNWz+M9MP8y5x8cR\n"
            + "5LXy6P4MCgYArcthAPyWki8NLRVyHY9CgNWmo9z4TG0wWgvZzx5qmI/ymd2P0avOm4z4XhxAUIZnZ6fQ\n"
            + "3mCQn8e8iDxpqyGtH7833G14CHzgOouu9QtV5We0UjfRZMo1WzbbmS05VNXD/1D/CHc8Lnqv43hRyo9i\n"
            + "47xC7qMU/bR7RXvdPBkvw8Q==\";";
    /**
     * 商户openApi申请所得appid
     */
    private static final String APP_ID = "7e773fb0-04b5-47ef-a99a-856d7f2e6a61";
    /**
     * 商户openApi申请所得secret
     */
    private static final String SECRET = "2760c355-ab78-4234-bb27-8734f6d6fa24";
    /**
     * 摘要算法
     */
    private static final String VERIFY = "SHA256withRSAVerify";
    /**
     * 收银台地址
     */
    private static final String URL = "http://99.12.222.108:8088/skt/exima/cashier/generateurl";

    public JSONObject request(JSONObject reqVo) {
        String resp = httpClientPost(buildHeader(sha256Signature(reqVo.toJSONString())), reqVo.toJSONString(), URL);
        return JSON.parseObject(resp);
    }

    /**
     * 构建请求头
     *
     * @param sign 业务报文摘要
     * @return Http请求头
     */
    private Map<String, List<String>> buildHeader(String sign) {
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        Map<String, String> headerNeedMd5Data = new HashMap<>(4);
        headerNeedMd5Data.put("appid", APP_ID);
        headerNeedMd5Data.put("secret", SECRET);
        headerNeedMd5Data.put("sign", sign);
        headerNeedMd5Data.put("timestamp", timestamp);
        String headerNeedMd5SortStr = buildSortData(headerNeedMd5Data);
        Map<String, List<String>> header = new HashMap<>(4);
        header.put("appid", Collections.singletonList(APP_ID));
        header.put("timestamp", Collections.singletonList(timestamp));
        header.put("apisign",
            Collections.singletonList(sha256WithRSAWithBase64Encode(headerNeedMd5SortStr, RSA_PRI_KEY)));
        header.put("sign", Collections.singletonList(sign));
        // header.put("verify",Collections.singletonList(VERIFY));
        return header;
    }

    /**
     * RSA加签
     *
     * @param str          待加签报文
     * @param base64PriKey RSA私钥
     * @return 签名字符串
     */
    public String sha256WithRSAWithBase64Encode(String str, String base64PriKey) {
        Sign sign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, base64PriKey, null);
        byte[] signDataByte = sign.sign(str.getBytes(StandardCharsets.UTF_8));
        return Base64.encode(signDataByte);
    }

    /**
     * 忽略大小写按照key1=value1&key2=value2组装参数
     */
    public String buildSortData(Map<String, String> map) {
        List<String> keys = new ArrayList<>(map.keySet());
        StringBuilder content = new StringBuilder();
        Collections.sort(keys);
        int index = 0;
        for (String key : keys) {
            String value = map.get(key);
            if (null != key && null != value) {
                content.append(index == 0 ? StrUtil.EMPTY : "&").append(key).append("=").append(value);
                index++;
            }
        }
        return content.toString();
    }

    /**
     * sha256 摘要签名
     *
     * @param src
     * @return
     */
    public String sha256Signature(String src) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
            messageDigest.update(src.getBytes(StandardCharsets.UTF_8));
            byte[] bytes = messageDigest.digest();
            return toHexString(bytes);
        } catch (Exception e) {
            throw new RuntimeException("签名计算出现异常");
        }
    }

    /**
     * httpclient post request
     *
     * @param header http headers
     * @param body   http post body
     * @param url    http post url
     * @return
     */
    public String httpClientPost(Map<String, List<String>> header, String body, String url) {
        log.info("HttpVisitor body is {},header is {},url is {}", body, header, url);
        try {
            HttpResponse httpResp =
                HttpRequest.post(url).body(body, ContentType.JSON.toString()).header(header).timeout(10000)
                    .setReadTimeout(30000).execute();
            if (200 != httpResp.getStatus()) {
                log.error("请求失败：status is [{}],message is [{}]", httpResp.getStatus(), httpResp.body());
                // TODO 商户自定义错误处理
                /**
                 * 400 一般验签失败
                 * 401 api网关权限问题
                 * 403 一般为url、参数等错误
                 */
            }
            String cmbBodySign = httpResp.headers().get("CMB-BodySign").get(0);
            if (!StringUtils.isEmpty(cmbBodySign)) {
                // 商户验签
                Sign mySign = SecureUtil.sign(SignAlgorithm.SHA256withRSA, null,
                    "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuPXgoY8+Zb66rOZv1V+AydOeZjCneUWCZO7\n"
                        + "I89oUce1BqW2idpq60yaLrW/8DsfU5ibzPsJ4ga8EOtP6i9YE4rkk1OzXVKNRfYHiC1rXLX+hwc6bmiu\n"
                        + "86f7J3jRUmSxe1QGJwIyPekIXlXOoLYM5QgKPmV41a8AgxGOUTb5IT4XPwy65aL39VR2l3KjbUp+E4m+\n"
                        + "NoyE3nm+iJZ6x3/KCi4o8F+VP6aYsqDAwcF2Wx1ezoFz/0WYkWO/KEBIt/SWGbAi/wGeyROgB/pz3XSD\n"
                        + "akY4o449LFAbI893v/Zo1zGLp4tS+s9cus+XOYBtEpg2Z7dCxN5inOqJdr7dKjOBZeQIDAQAB\");"); boolean result =
                    mySign.verify(httpResp.body().getBytes(StandardCharsets.UTF_8), Base64.decode(cmbBodySign));
                if (!result) {
                    log.error("验签失败");
                    // TODO 商户自定义错误处理
                } else {
                    log.info("验签成功");
                }
            } String respBody = httpResp.body();
            log.info("HttpVisitor resp = {}", respBody);
            return respBody;
        } catch (Exception e) {
            log.error("Error: http post error: body is {},header is {},url is {},e = ", body, header, url, e);
            throw e;
        }
    }

    public static void main(String[] args) {
        JSONObject reqVo = new JSONObject();
        reqVo.put("merchId", "JB0003");
        reqVo.put("branchNo", "0755");
        reqVo.put("returnUrl", "https://qr.alipay.com/bax067078eozcn3ekgag0072");
        reqVo.put("payNo", "123456789");
        reqVo.put("payTypeList", new ArrayList<String>() {{
            add("7");
            add("8");
        }});
        reqVo.put("needCashier", "0");
        OpenApiDemoService openApiDemoService = new OpenApiDemoService();
        System.out.println("result is " + openApiDemoService.request(reqVo));
    }
}
